package org.irri.smta.ui.bean;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.irri.smta.common.Constants;
import org.irri.smta.domain.SmtaReport;
import org.irri.smta.service.ISmtaReportService;
import org.irri.smta.util.BeanUtils;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.Specifications;

@Named("smtaReportBean")
@SessionScoped
public class SmtaReportBean extends SelectableTableBeanBase<SmtaReport> {

	private static final long serialVersionUID = 1L;
	private static final Logger LOGGER = LoggerFactory
			.getLogger(SmtaReportBean.class);

	private static final String PARAM_ID = "id";
	private static final String PARAM_SYMBOL = "symbol";
	private static final String PARAM_REPORTED = "reportedToTreaty";
	
	@Inject
	@Named("smtaReportService")
	private ISmtaReportService<SmtaReport, Long> smtaReportService;

	private LazyDataModel<SmtaReport> smtaReportDataModel = null;
	private SmtaReport selectedSmtaReport = new SmtaReport();
	private SmtaReport newSmtaReport = new SmtaReport();
	private BeanUtils beanUtils = new BeanUtils();
	private String smtaId = null;

	public SmtaReportBean() {
		super();
		setViewName(Constants.SMTA_REPORT_HOME_VIEW_NAME);
	}

	@PostConstruct
	public void init() {
		LOGGER.debug("init()");
		selectedSmtaReport = new SmtaReport();
		newSmtaReport = new SmtaReport();
	}

	public ISmtaReportService<SmtaReport, Long> getSmtaReportService() {
		return smtaReportService;
	}

	public String getSmtaId() {
		return smtaId;
	}

	public void setSmtaId(String smtaId) {
		this.smtaId = smtaId;
	}

	public SmtaReport getSelectedSmtaReport() {
		if (selectedSmtaReport == null) {
			selectedSmtaReport = new SmtaReport();
		}
		return selectedSmtaReport;
	}

	public void setSelectedSmtaReport(SmtaReport smtaReport) {
		this.selectedSmtaReport = smtaReport;
	}

	public SmtaReport getNewSmtaReport() {
		if (newSmtaReport == null) {
			newSmtaReport = new SmtaReport();
		}
		return newSmtaReport;
	}

	public void setNewSmtaReport(SmtaReport newSmtaReport) {
		this.newSmtaReport = newSmtaReport;
	}

	public LazyDataModel<SmtaReport> getAllSmtaReports() {
		LOGGER.debug("LazyDataModel<SmtaReport> getAllSmtaReports()");
		if (smtaReportDataModel == null) {
			smtaReportDataModel = new LazyDataModel<SmtaReport>() {
				private static final long serialVersionUID = 1L;

				@Override
				public List<SmtaReport> load(int rowIndex, int pageSize,
						String sortField, SortOrder sortOrder,
						Map<String, String> filters) {
					LOGGER.debug("List<SmtaReport> load(int rowIndex, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters)");
					List<SmtaReport> data = new ArrayList<SmtaReport>();
					if (rowIndex < 0) {
						rowIndex = 0;
					}
					if (pageSize <= 0) {
						pageSize = Constants.DEFAULT_PAGE_SIZE;
					}

					HttpServletRequest request = (HttpServletRequest) FacesContext
							.getCurrentInstance().getExternalContext()
							.getRequest();
					String paramSymbol = request.getParameter(PARAM_SYMBOL);
					if (paramSymbol != null) {
						filters.put(PARAM_SYMBOL, paramSymbol);
					}
					String paramReported = request.getParameter(PARAM_REPORTED);
					if (paramReported != null) {
						filters.put(PARAM_REPORTED, paramReported);
					}

					// filter
					Specification<SmtaReport> symbolSpecification = null;
					Specification<SmtaReport> reportedSpecification = null;
					Iterator<String> it = filters.keySet().iterator();
					if (it.hasNext()) {
						String filterProperty = it.next();
						String filterValue = filters.get(filterProperty);
						Class<? extends SmtaReport> clazz = SmtaReport.class;
						Field field = null;
						try {
							field = clazz.getDeclaredField(filterProperty);
						} catch (SecurityException e) {
							LOGGER.error(e.getMessage());
						} catch (NoSuchFieldException e) {
							LOGGER.error(e.getMessage());
						}
						if (field != null) {
							if (field.getName().equalsIgnoreCase(PARAM_SYMBOL)) {
								symbolSpecification = symbolIsLike(filterValue);
							} else if (field.getName().equalsIgnoreCase(PARAM_REPORTED)) {
								reportedSpecification = reportedIsEqual(filterValue);
							}
						}
					}

					int pageIndex = rowIndex / pageSize;
					Pageable pageable = new PageRequest(pageIndex, pageSize,
							new Sort(Sort.Direction.ASC, PARAM_SYMBOL));
					List<SmtaReport> list = null;
					Specifications<SmtaReport> specifications = null;
					if (symbolSpecification != null) {
						if (specifications == null) {
							specifications = Specifications.where(symbolSpecification);
						}
					}
					if (reportedSpecification != null) {
						if (specifications == null) {
							specifications = Specifications.where(reportedSpecification);
						} else {
							specifications = specifications.and(reportedSpecification);
						}
					}
					if (specifications != null) {
						list = smtaReportService.findAll(specifications,
								pageable);
					} else {
						list = smtaReportService.findAll(pageable);
					}
					data.addAll(list);

					// rowCount
					Long rowCount = smtaReportService.getRowCount();
					Integer dataSize = rowCount != null ? rowCount.intValue()
							: null;
					this.setRowCount(dataSize);
					// pageSize
					this.setPageSize(pageSize);

					return data;
				}
			};
		}
		return smtaReportDataModel;
	}

	public static Specification<SmtaReport> symbolIsLike(final String searchTerm) {
		return new Specification<SmtaReport>() {
			@Override
			public Predicate toPredicate(Root<SmtaReport> root,
					CriteriaQuery<?> query, CriteriaBuilder cb) {
				String likePattern = getLikePattern(searchTerm);
				return cb.like(cb.lower(root.<String> get(PARAM_SYMBOL)),
						likePattern);
			}

			private String getLikePattern(final String searchTerm) {
				StringBuilder pattern = new StringBuilder();
				pattern.append("%");
				if (searchTerm != null) {
					pattern.append(searchTerm.toLowerCase());
				}
				pattern.append("%");
				return pattern.toString();
			}
		};
	}

	public static Specification<SmtaReport> reportedIsEqual(final String searchTerm) {
		return new Specification<SmtaReport>() {
			@Override
			public Predicate toPredicate(Root<SmtaReport> root,
					CriteriaQuery<?> query, CriteriaBuilder cb) {
				return cb.equal(root.<String> get(PARAM_REPORTED),
						new Boolean(searchTerm));
			}
		};
	}

	@Override
	public Object getRowKey(SmtaReport object) {
		return object.getId();
	}

	@Override
	public SmtaReport getRowData(String rowKey) {
		return smtaReportService.findById(new Long(rowKey));
	}

	public void openMaterialView() {
		LOGGER.debug("openMaterialView()");
		FacesContext facesContext = FacesContext.getCurrentInstance();
		if (facesContext != null) {
			HttpSession session = (HttpSession) facesContext
					.getExternalContext().getSession(false);
			if (session != null && getSelectedSmtaReport() != null) {
				session.setAttribute(PARAM_ID, getSelectedSmtaReport().getId());
			}
			beanUtils.navigateToView(Constants.MATERIAL_VIEW_NAME);
		}
	}

	public void openMaterialView(Long smtaReportId) {
		LOGGER.debug("openMaterialView(String smtaReportId): " + smtaReportId);
		if (smtaReportId != null) {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			if (facesContext != null) {
				HttpSession session = (HttpSession) facesContext
						.getExternalContext().getSession(false);
				if (session != null) {
					session.setAttribute(PARAM_ID, smtaReportId);
				}
				beanUtils.navigateToView(Constants.MATERIAL_VIEW_NAME);
			}
		}
	}
	
	public void setAsUnreported() {
		LOGGER.debug("setAsUnreported()");
		if (getSelectedSmtaReport() != null) {
			String symbol = getSelectedSmtaReport().getSymbol();
			try {
				smtaReportService.setAsUreported(symbol);
			} catch (Exception e) {
				e.printStackTrace();
			}
			beanUtils.navigateToView(Constants.SMTA_REPORT_HOME_VIEW_NAME);
		}
	}

	public void setAsReported() {
		LOGGER.debug("setAsReported()");
		if (getSelectedSmtaReport() != null) {
			String symbol = getSelectedSmtaReport().getSymbol();
			try {
				smtaReportService.setAsReported(symbol);
			} catch (Exception e) {
				e.printStackTrace();
			}
			beanUtils.navigateToView(Constants.SMTA_REPORT_HOME_VIEW_NAME);
		}
	}

}
